package com.apes.fico.engine.timerTask;

import com.alibaba.fastjson.JSONObject;
import com.apes.fico.engine.model.ReduceVoucher;
import com.apes.fico.engine.model.ReduceVoucherItem;
import com.apes.fico.engine.model.TempVoucher;
import com.apes.fico.engine.model.TempVoucherItem;
import com.apes.fico.engine.repository.ReduceVoucherRepository;
import com.apes.fico.engine.repository.TempVoucherRepository;
import com.apes.fico.masterdata.gl.model.AccountingModel;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.mq.MQUtil;
import com.apes.framework.plugin.mq.annotation.Consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/*
* 按天/月归约, 先归约到归约凭证
* */
@Service
public class ReduceToReduceVoucherImpl extends DomainService implements Reduce {

    @Autowired
    ReduceVoucherRepository reduceVoucherRepository;


    @Override
    public boolean correctCycle(String cycle) {
        return !AccountingModel.RT.equals(cycle);
    }

    @Override
    public void reduce(TempVoucher tempVoucher) {
        String cycle = "";
        String cycleValue = "";
        try {
            Date postDate = tempVoucher.getPostDate();
            cycle = tempVoucher.getVoucherTemplate().getCycle();
            cycleValue = getCycleValue(cycle,postDate);
            ReduceVoucher reduceVoucher;
            // 按归约值查询未完成的单据
            reduceVoucher = reduceVoucherRepository.findUniqueVoucherIsNotDone(
                    tempVoucher.getCompany().getId(), tempVoucher.getVoucherTemplate().getId(),tempVoucher.getRemark(),
                    tempVoucher.getAccountingVoucherType().getId(),cycleValue,cycle
            );
            if(reduceVoucher != null) {
                updateReduceVoucher(reduceVoucher,tempVoucher);
            }else {
                reduceVoucher = BasisService.toReduceVoucher(tempVoucher,cycle,cycleValue);
            }

            saveReduceVoucher(reduceVoucher);

            BasisService.updateTempVoucherState(tempVoucher);
        }catch (Exception e) {
            // 发送错误处理 更新haveError 或者 新增, 并写 haveError
            MQUtil.publish("reduceToReduce.process.error","原始凭证生成归约凭证错误处理",
                    mapper("tempVoucherId",tempVoucher.getId(),"companyId",tempVoucher.getCompany().getId(),"voucherTemplateId",tempVoucher.getVoucherTemplate().getId(),
                           "remark",tempVoucher.getRemark(), "accountingVoucherTypeId",tempVoucher.getAccountingVoucherType().getId(),"cycleValue",cycleValue,"cycle",cycle));
            throw e;
        }

    }


    /*
    *  获取周期值
    * */
    private String getCycleValue(String cycle, Date postDate) {
        String cycleValue;
        if(AccountingModel.D.equals(cycle)) { // 天
            cycleValue = DateUtil.format(postDate,"yyyyMMdd");
        }else if (AccountingModel.M.equals(cycle)) { // 月
            cycleValue = DateUtil.format(postDate,"yyyyMM");
        }else {
            throw new RuntimeException("结转周期错误,请检查！");
        }
        return cycleValue;
    }



    /*
    * 更新归约凭证,归约凭证分录
    * */
    private void updateReduceVoucher(ReduceVoucher reduceVoucher,TempVoucher tempVoucher) {
        reduceVoucher.changeCreditTotal(tempVoucher.getCreditTotal());
        reduceVoucher.changeDebitTotal(tempVoucher.getDebitTotal());
        List<ReduceVoucherItem> reduceVoucherItems = reduceVoucher.getVoucherItemList();
        List<TempVoucherItem> tempVoucherItems = tempVoucher.getVoucherItemList();
        TempVoucherItem tempVoucherItem;
        ReduceVoucherItem reduceVoucherItem;
        boolean isHave;
        for (int i = 0, temLen = tempVoucherItems.size(); i < temLen; i++) {
            tempVoucherItem = tempVoucherItems.get(i);
            isHave = false;
            for (int j = 0, reduceLen = reduceVoucherItems.size(); j < reduceLen; j++) {
                reduceVoucherItem = reduceVoucherItems.get(j);
                if(reduceVoucherItem.checkUnique(tempVoucherItem.getAccountingOperatingChart().getId(),tempVoucherItem.getSummary(),
                        tempVoucherItem.getCollectAux(), tempVoucherItem.getVoucherTemplateEntry().getId())) {
                    reduceVoucherItem.changeCredit(tempVoucherItem.getCredit());
                    reduceVoucherItem.changeDebit(tempVoucherItem.getDebit());
                    isHave = true;
                    break;
                }
            }
            if(!isHave) {
                ReduceVoucherItem newReduceVoucherItem = SpringManager.getBean(BasisService.class).toReduceVoucherItem(tempVoucherItem,reduceVoucher);
                reduceVoucherItems.add(newReduceVoucherItem);
            }
        }
        reduceVoucher.setVoucherItemList(reduceVoucherItems);
    }


    /*
    * 保存/更新归约凭证
    * */
    private void saveReduceVoucher(ReduceVoucher reduceVoucher) {
        reduceVoucher.checkCycle(reduceVoucher.getCycle());
        reduceVoucherRepository.saveAndFlush(reduceVoucher);
    }


    /*
    * 记录有错误归约凭证
    * */
    @Consumer(topic = "reduceToReduce.process.error")
    public void processErrorVoucher(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        String companyId = requestJO.getString("companyId");
        String voucherTemplateId = requestJO.getString("voucherTemplateId");
        String remark = requestJO.getString("remark");
        String accountingVoucherTypeId = requestJO.getString("accountingVoucherTypeId");
        String cycleValue = requestJO.getString("cycleValue");
        String cycle = requestJO.getString("cycle");
        ReduceVoucher reduceVoucher = reduceVoucherRepository.findUniqueVoucherIsNotDone(companyId,voucherTemplateId,remark,accountingVoucherTypeId,cycleValue,cycle);
        if(reduceVoucher == null) {
            String tempVoucherId = requestJO.getString("tempVoucherId");
            reduceVoucher = BasisService.toReduceVoucher(SpringManager.getBean(TempVoucherRepository.class).findOne(tempVoucherId),cycle,cycleValue);
            reduceVoucher.setCreditTotal(0);
            reduceVoucher.setDebitTotal(0);
            reduceVoucher.getVoucherItemList().forEach(
                    (item) -> {
                        item.setCredit(0);
                        item.setDebit(0);
                    }
            );
        }
        reduceVoucher.setHaveError(true);
        saveReduceVoucher(reduceVoucher);
    }



}
